home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Gfx / Edit / TSMorph / src / ilbmr.c < prev    next >
C/C++ Source or Header  |  1994-10-30  |  11KB  |  381 lines

  1. /* ilbmr.c --- ILBM loading routines for use with iffparse */
  2.  
  3. /*----------------------------------------------------------------------*
  4.  * ILBMR.C  Support routines for reading ILBM files.
  5.  * (IFF is Interchange Format File.)
  6.  *
  7.  * Based on code by Jerry Morrison and Steve Shaw, Electronic Arts.
  8.  * This software is in the public domain.
  9.  * Modified for iffparse.library 05/90
  10.  * This version for the Commodore-Amiga computer.
  11.  *
  12.  * 37.9 04/92
  13.  *----------------------------------------------------------------------*/
  14.  
  15. // Minor changes to error handling and other stuff MJP
  16.  
  17. #define INTUI_V36_NAMES_ONLY
  18.  
  19. #include "iffp/ilbm.h"
  20. #include "iffp/packer.h"
  21. #include "iffp/ilbmapp.h"
  22.  
  23. #define movmem CopyMem
  24.  
  25. #define MaxSrcPlanes (25)
  26.  
  27. extern struct Library *GfxBase;
  28.  
  29. /*---------- loadbody ---------------------------------------------------*/
  30.  
  31. LONG loadbody(iff, bitmap, bmhd)
  32. struct IFFHandle *iff;
  33. struct BitMap *bitmap;
  34. BitMapHeader *bmhd;
  35.     {
  36.     BYTE *buffer;
  37.     ULONG bufsize;
  38.     LONG error = 1;
  39.  
  40.     D(bug("In loadbody\n"));
  41.  
  42.     if(!(currentchunkis(iff,ID_ILBM,ID_BODY)))
  43.         {
  44.         message(SI(MSG_IFFP_NOBODY),NULL,4);    /* Maybe it's a palette */        // MJP 4 = HE_IFFBODY
  45.         return(IFF_OKAY);
  46.         }
  47.  
  48.     if((bitmap)&&(bmhd))
  49.         {
  50.         D(bug("Have bitmap and bmhd\n"));
  51.  
  52.         bufsize = MaxPackedSize(RowBytes(bmhd->w)) << 4;
  53.             if(!(buffer = AllocMem(bufsize,0L)))
  54.         {
  55.         D(bug("Buffer alloc of %ld failed\n",bufsize));
  56.         return(IFFERR_NOMEM);
  57.         }
  58.         error = loadbody2(iff, bitmap, NULL, bmhd, buffer, bufsize);
  59.         D(bug("Returned from getbody, error = %ld\n",error));
  60.         }
  61.     FreeMem(buffer,bufsize);
  62.     return(error);
  63.     }
  64.  
  65.  
  66. /* like the old GetBODY */
  67. LONG loadbody2(iff, bitmap, mask, bmhd, buffer, bufsize)
  68. struct IFFHandle *iff;
  69. struct BitMap *bitmap;
  70. BYTE *mask;
  71. BitMapHeader *bmhd;
  72. BYTE *buffer;
  73. ULONG bufsize;
  74.    {
  75.    UBYTE srcPlaneCnt = bmhd->nPlanes;   /* Haven't counted for mask plane yet*/
  76.    WORD srcRowBytes = RowBytes(bmhd->w);
  77.    WORD destRowBytes = bitmap->BytesPerRow;
  78.    LONG bufRowBytes = MaxPackedSize(srcRowBytes);
  79.    int nRows = bmhd->h;
  80.    WORD compression = bmhd->compression;
  81.    register int iPlane, iRow, nEmpty;
  82.    register WORD nFilled;
  83.    BYTE *buf, *nullDest, *nullBuf, **pDest;
  84.    BYTE *planes[MaxSrcPlanes]; /* array of ptrs to planes & mask */
  85.    struct ContextNode *cn;
  86.  
  87.    D(bug("srcRowBytes = %ld\n",srcRowBytes));
  88.  
  89.    cn = CurrentChunk(iff);
  90.  
  91.    if (compression > cmpByteRun1)
  92.       return(CLIENT_ERROR);
  93.  
  94.    D(bug("loadbody2: compression=%ld srcBytes=%ld bitmapBytes=%ld\n",
  95.         compression, srcRowBytes, bitmap->BytesPerRow));
  96.    D(bug("loadbody2: bufsize=%ld bufRowBytes=%ld, srcPlaneCnt=%ld\n",
  97.             bufsize, bufRowBytes, srcPlaneCnt));
  98.  
  99.    /* Complain if client asked for a conversion GetBODY doesn't handle.*/
  100.    if ( srcRowBytes  >  bitmap->BytesPerRow  ||
  101.          bufsize < bufRowBytes * 2  ||
  102.          srcPlaneCnt > MaxSrcPlanes )
  103.       return(CLIENT_ERROR);
  104.  
  105.    D(bug("loadbody2: past conversion checks\n"));
  106.  
  107.    if (nRows > bitmap->Rows)   nRows = bitmap->Rows;
  108.  
  109.    D(bug("loadbody2: srcRowBytes=%ld, srcRows=%ld, srcDepth=%ld, destDepth=%ld\n",
  110.         srcRowBytes, nRows, bmhd->nPlanes, bitmap->Depth));
  111.    
  112.    /* Initialize array "planes" with bitmap ptrs; NULL in empty slots.*/
  113.    for (iPlane = 0; iPlane < bitmap->Depth; iPlane++)
  114.       planes[iPlane] = (BYTE *)bitmap->Planes[iPlane];
  115.    for ( ;  iPlane < MaxSrcPlanes;  iPlane++)
  116.       planes[iPlane] = NULL;
  117.  
  118.    /* Copy any mask plane ptr into corresponding "planes" slot.*/
  119.    if (bmhd->masking == mskHasMask)
  120.     {
  121.           if (mask != NULL)
  122.              planes[srcPlaneCnt] = mask;  /* If there are more srcPlanes than
  123.                * dstPlanes, there will be NULL plane-pointers before this.*/
  124.           else
  125.              planes[srcPlaneCnt] = NULL;  /* In case more dstPlanes than src.*/
  126.           srcPlaneCnt += 1;  /* Include mask plane in count.*/
  127.           }
  128.  
  129.    /* Setup a sink for dummy destination of rows from unwanted planes.*/
  130.    nullDest = buffer;
  131.    buffer  += srcRowBytes;
  132.    bufsize -= srcRowBytes;
  133.  
  134.    /* Read the BODY contents into client's bitmap.
  135.     * De-interleave planes and decompress rows.
  136.     * MODIFIES: Last iteration modifies bufsize.*/
  137.  
  138.    buf = buffer + bufsize;  /* Buffer is currently empty.*/
  139.    for (iRow = nRows; iRow > 0; iRow--)
  140.     {
  141.           for (iPlane = 0; iPlane < srcPlaneCnt; iPlane++)
  142.         {
  143.          pDest = &planes[iPlane];
  144.  
  145.             /* Establish a sink for any unwanted plane.*/
  146.             if (*pDest == NULL)
  147.         {
  148.             nullBuf = nullDest;
  149.                 pDest   = &nullBuf;
  150.                 }
  151.  
  152.             /* Read in at least enough bytes to uncompress next row.*/
  153.             nEmpty  = buf - buffer;      /* size of empty part of buffer.*/
  154.             nFilled = bufsize - nEmpty;      /* this part has data.*/
  155.         if (nFilled < bufRowBytes)
  156.         {
  157.             /* Need to read more.*/
  158.  
  159.             /* Move the existing data to the front of the buffer.*/
  160.             /* Now covers range buffer[0]..buffer[nFilled-1].*/
  161.                 movmem(buf, buffer, nFilled);  /* Could be moving 0 bytes.*/
  162.  
  163.                 if(nEmpty > ChunkMoreBytes(cn))
  164.             {
  165.                        /* There aren't enough bytes left to fill the buffer.*/
  166.                        nEmpty = ChunkMoreBytes(cn);
  167.                        bufsize = nFilled + nEmpty;  /* heh-heh */
  168.                        }
  169.  
  170.             /* Append new data to the existing data.*/
  171.                 if(ReadChunkBytes(iff, &buffer[nFilled], nEmpty) < nEmpty)
  172.             return(CLIENT_ERROR);
  173.  
  174.                 buf     = buffer;
  175.             nFilled = bufsize;
  176.             nEmpty  = 0;
  177.             }
  178.  
  179.          /* Copy uncompressed row to destination plane.*/
  180.             if(compression == cmpNone)
  181.         {
  182.                 if(nFilled < srcRowBytes)  return(IFFERR_MANGLED);
  183.             movmem(buf, *pDest, srcRowBytes);
  184.             buf    += srcRowBytes;
  185.                 *pDest += destRowBytes;
  186.                 }
  187.         else
  188.         {
  189.              /* Decompress row to destination plane.*/
  190.                 if ( unpackrow(&buf, pDest, nFilled,  srcRowBytes) )
  191.                     /*  pSource, pDest, srcBytes, dstBytes  */
  192.                        return(IFFERR_MANGLED);
  193.             else *pDest += (destRowBytes - srcRowBytes);
  194.         }
  195.         }
  196.     }
  197.    return(IFF_OKAY);
  198.    }
  199.  
  200.  
  201. /* ----------- getcolors ------------- */
  202.  
  203. /* getcolors - allocates a ilbm->colortable for at least 32 registers
  204.  *      and loads CMAP colors into it, setting ilbm->ncolors to number
  205.  *      of colors actually loaded.
  206.  */ 
  207. LONG getcolors(struct ILBMInfo *ilbm)
  208.     {
  209.     struct IFFHandle    *iff;
  210.     int error = 1;
  211.  
  212.     if(!(iff=ilbm->ParseInfo.iff))    return(CLIENT_ERROR);
  213.  
  214.     if(!(error = alloccolortable(ilbm)))
  215.        error = loadcmap(iff, ilbm->colortable, &ilbm->ncolors,ilbm);
  216.     if(error) freecolors(ilbm);
  217.     D(bug("getcolors: error = %ld\n",error));
  218.     return(error);
  219.     }
  220.  
  221. /* alloccolortable - allocates ilbm->colortable and sets ilbm->ncolors
  222.  *    to the number of colors we have room for in the table.
  223.  */ 
  224.  
  225. LONG alloccolortable(struct ILBMInfo *ilbm)
  226.     {
  227.     struct IFFHandle    *iff;
  228.     struct    StoredProperty    *sp;
  229.  
  230.     LONG    error = CLIENT_ERROR;
  231.     ULONG    ctabsize;
  232.     USHORT    ncolors;
  233.  
  234.     if(!(iff=ilbm->ParseInfo.iff))    return(CLIENT_ERROR);
  235.  
  236.     if(sp = FindProp (iff, ID_ILBM, ID_CMAP))
  237.         {
  238.         /*
  239.          * Compute the size table we need
  240.          */
  241.         ncolors = sp->sp_Size / 3;        /* how many in CMAP */
  242. //        ncolors = MAX(ncolors, 32);    MJP - may be more than 32 colours
  243.  
  244.         ctabsize = ncolors * sizeof(Color4);
  245.         if ((ilbm->colortable = 
  246.            (Color4 *)AllocMem(ctabsize,MEMF_CLEAR|MEMF_PUBLIC)) &&    // MJP
  247.            (ilbm->RGB = AllocMem(ncolors*4,MEMF_CLEAR|MEMF_PUBLIC))) // RGB colors
  248.             {
  249.             ilbm->ncolors = ncolors;
  250.             ilbm->ctabsize = ctabsize;
  251.             error = 0L;
  252.             }
  253.         else {
  254.              error = IFFERR_NOMEM;
  255.             if (ilbm->colortable) {
  256.                 FreeMem(ilbm->colortable,ctabsize);
  257.                 ilbm->colortable = NULL;
  258.             }
  259.         }
  260.     }
  261.     D(bug("alloccolortable for %ld colors: error = %ld\n",ncolors,error));
  262.     return(error);
  263.     }
  264.  
  265.  
  266. void freecolors(struct ILBMInfo *ilbm)
  267.     {
  268.     if(ilbm->colortable)
  269.         {
  270.         FreeMem(ilbm->colortable, ilbm->ctabsize);
  271.         }
  272.     if (ilbm->RGB) {
  273.         FreeMem(ilbm->RGB,ilbm->ncolors*4);
  274.     }
  275.     ilbm->RGB = NULL;
  276.     ilbm->colortable = NULL;
  277.     ilbm->ctabsize = 0;
  278.     }
  279.  
  280.  
  281.  
  282. /* Passed IFFHandle, pointer to colortable array, and pointer to
  283.  * a USHORT containing number of colors caller has space to hold,
  284.  * loads the colors and sets pNcolors to the number actually read.
  285.  *
  286.  * NOTE !!! - Old GetCMAP passed a pointer to a UBYTE for pNcolors
  287.  *            This one is passed a pointer to a USHORT
  288.  */
  289. LONG loadcmap(struct IFFHandle *iff, WORD *colortable,USHORT *pNcolors,struct ILBMInfo *ilbm)
  290.     {
  291.     register struct StoredProperty    *sp;
  292.     register LONG            idx;
  293.     register ULONG            ncolors;
  294.     register UBYTE            *rgb;
  295.     LONG                r, g, b;
  296.     UBYTE *rgb8;    // MJP RGB colours
  297.  
  298.     if(!(colortable))
  299.         {
  300. //        message(SI(MSG_IFFP_NOCOLORS),NULL);        // MJP
  301.         return(1);
  302.         }
  303.  
  304.     if(!(sp = FindProp (iff, ID_ILBM, ID_CMAP)))    return(1);
  305.  
  306.     rgb = sp->sp_Data;
  307.     ncolors = sp->sp_Size / sizeofColorRegister;
  308.     if(*pNcolors < ncolors)    ncolors = *pNcolors;
  309.     *pNcolors = ncolors;
  310.     rgb8 = ilbm->RGB;    // RGB colours
  311.  
  312.     idx = 0;
  313.         while (ncolors--) 
  314.                 {
  315.                 *rgb8++ = 0;    // also set up RGB colours
  316.                 r = ((*rgb8++ = *rgb++) & 0xF0) << 4;
  317.                 g = (*rgb8++ = *rgb++) & 0xF0;
  318.                 b = (*rgb8++ = *rgb++) >> 4;
  319.                 colortable[idx] = r | g | b;
  320.                 idx++;
  321.                 }
  322.         return(0);
  323.         }
  324. /*
  325.  * Returns CAMG or computed mode for storage in ilbm->camg
  326.  *
  327.  * ilbm->Bmhd structure must be initialized prior to this call.
  328.  */
  329. ULONG getcamg(struct ILBMInfo *ilbm)
  330.     {
  331.     struct IFFHandle *iff;
  332.     struct StoredProperty *sp;
  333.     UWORD  wide,high,deep;
  334.     ULONG modeid = 0L;
  335.  
  336.         if(!(iff=ilbm->ParseInfo.iff))    return(0L);
  337.  
  338.     wide = ilbm->Bmhd.pageWidth;
  339.     high = ilbm->Bmhd.pageHeight;
  340.     deep = ilbm->Bmhd.nPlanes;
  341.  
  342.     D(bug("Getting CAMG for w=%ld h=%ld d=%ld ILBM\n",wide,high,deep));
  343.  
  344.         /*
  345.          * Grab CAMG's idea of the viewmodes.
  346.          */
  347.         if (sp = FindProp (iff, ID_ILBM, ID_CAMG))
  348.                 {
  349.                 modeid = (* (ULONG *) sp->sp_Data);
  350.  
  351.                 /* knock bad bits out of old-style 16-bit viewmode CAMGs
  352.                  */
  353.                 if((!(modeid & MONITOR_ID_MASK))||
  354.           ((modeid & EXTENDED_MODE)&&(!(modeid & 0xFFFF0000))))
  355.                    modeid &= 
  356.             (~(EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE));
  357.  
  358.                 /* check for bogus CAMG like DPaintII brushes
  359.                  * with junk in upper word and extended bit
  360.                  * not set in lower word.
  361.                  */
  362.                 if((modeid & 0xFFFF0000)&&(!(modeid & 0x00001000))) sp=NULL;
  363.                 }
  364.  
  365.         if(!sp) {
  366.                 /*
  367.                  * No CAMG (or bad CAMG) present; use computed modes.
  368.                  */
  369.                 if (wide >= 640)        modeid = HIRES;
  370.                 if (high >= 400)        modeid |= LACE;
  371.                 if (deep == 6)
  372.                         {
  373.                         modeid |= ilbm->EHB ? EXTRA_HALFBRITE : HAM;
  374.                         }
  375.         D(bug("No CAMG found - using mode $%08lx\n",modeid));
  376.                 }
  377.  
  378.     D(bug("getcamg: modeid = $%08lx\n",modeid));
  379.     return(modeid);
  380.     }
  381.